package com.utooo.bid.controller;

import com.utooo.bid.common.ResponseCode;
import com.utooo.bid.model.CatalogVO;
import com.utooo.bid.model.ChatReq;
import com.utooo.bid.model.Result;
import com.utooo.bid.service.BidDocumentService;
import com.utooo.bid.service.RagAssistant;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.StreamingResponseHandler;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.chat.request.ChatRequest;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import dev.langchain4j.model.output.Response;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

@RestController
@RequestMapping("/plugin/api/bid")
@RequiredArgsConstructor
@Slf4j
public class BidDocController {

    private final BidDocumentService bidDocumentService;
    private final StreamingChatLanguageModel streamingChatLanguageModel;
    private final RagAssistant ragAssistant;

    @PostMapping("/upload")
    public Result<String> uploadFile(@RequestParam String bidId) {
        try {
            bidDocumentService.processBidDocument(bidId);
            return Result.success("上传成功，正在解析中...");
        } catch (IllegalArgumentException e) {
            log.warn("参数验证失败", e);
            return Result.error(ResponseCode.PARAM_ERROR.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("处理失败", e);
            return Result.error(ResponseCode.INTERNAL_ERROR);
        }
    }

    @PostMapping("/catalog/generate/{bidId}")
    public Result<String> generateBidCatalog(@PathVariable String bidId, @RequestParam int type) {
        try {
            bidDocumentService.generateBidCatalog(bidId, type);
            return Result.success("目录正在生成中...");
        } catch (IllegalArgumentException e) {
            log.warn("参数验证失败", e);
            return Result.error(ResponseCode.PARAM_ERROR.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("生成目录失败", e);
            return Result.error(ResponseCode.INTERNAL_ERROR.getCode(), "生成目录失败");
        }
    }

    @GetMapping("/catalog/{bidId}")
    public Result<List<CatalogVO>> getCatalog(@PathVariable String bidId, @RequestParam int type) {
        try {
            List<CatalogVO> catalogs = bidDocumentService.getCatalogTree(bidId, type);
            return Result.success(catalogs);
        } catch (Exception e) {
            log.error("获取目录失败", e);
            return Result.error(ResponseCode.INTERNAL_ERROR.getCode(), e.getMessage());
        }
    }

    @PostMapping("/catalog/update")
    public Result<String> updateBidCatalog(@RequestParam(required = false) String catalogId, @RequestParam String name, @RequestParam(required = false) String parentId) {
        try {
            bidDocumentService.updateBidCatalog(catalogId, name, parentId);
            return Result.success("更新成功");
        } catch (IllegalArgumentException e) {
            log.warn("参数验证失败", e);
            return Result.error(ResponseCode.PARAM_ERROR.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("修改目录失败", e);
            return Result.error(ResponseCode.INTERNAL_ERROR.getCode(), "修改目录失败");
        }
    }

    @PostMapping("/catalog/delete/{catalogId}")
    public Result<String> deleteBidCatalog(@PathVariable String catalogId) {
        try {
            bidDocumentService.deleteBidCatalog(catalogId);
            return Result.success("删除成功");
        } catch (IllegalArgumentException e) {
            log.warn("参数验证失败", e);
            return Result.error(ResponseCode.PARAM_ERROR.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("删除目录失败", e);
            return Result.error(ResponseCode.INTERNAL_ERROR.getCode(), "删除目录失败");
        }
    }

    @GetMapping(value = "/catalog/content/generate/{bidId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter genContentByBidCatalog(@PathVariable String bidId,
                                             @RequestParam int type,
                                             @RequestParam int useKnowledge,
                                             @RequestParam String companyId) {
        return bidDocumentService.genContentByBidCatalog(bidId, type, useKnowledge, companyId);
    }

    @PostMapping(value = "/content/generate/{bidId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter genBidContent(@PathVariable String bidId) {
        return bidDocumentService.genBidContent(bidId);
    }

//    @GetMapping("/catalog/content/generate/{bidId}")
//    public Flux<String> stream(@PathVariable String bidId,
//                               @RequestParam int type,
//                               @RequestParam int useKnowledge,
//                               @RequestParam String companyId,
//                               HttpServletResponse response) {
//        response.setCharacterEncoding("UTF-8");
//        return bidDocumentService.genBidContentReactive(bidId, type, useKnowledge, companyId);
//    }

    /*@GetMapping(value = "/chat/test")
    public Flux<String> testChat() {
        streamingChatLanguageModel.g("你好！");
    }*/

    @GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter chat(@RequestParam String question) {
        SseEmitter emitter = new SseEmitter(-1L);
        Flux<String> flux = ragAssistant.stream(Arrays.asList(UserMessage.from(question)));
        StringBuilder fullResponse = new StringBuilder();
        flux.subscribe(
                chunk -> {
                    try {
                        emitter.send(SseEmitter.event().data(chunk));
                        fullResponse.append(chunk);
                        log.debug("Sent chunk: {}", chunk);
                    } catch (IOException e) {
                        log.error("Failed to send SSE event", e);
                        emitter.completeWithError(e);
                    }
                },
                error -> {
                    log.error("Streaming error for question: {}", question, error);
                    emitter.completeWithError(error);
                },
                () -> {
                    try {
                        // 发送完成信号
                        String completeResponse = fullResponse.toString();
                        emitter.send(SseEmitter.event()
                                .name("complete")
                                .data("{\"status\": \"done\", \"content\": \"" + completeResponse + "\"}"));
                        log.info("Streaming completed for question: {}", question);
                    } catch (IOException e) {
                        log.error("Failed to send completion event", e);
                        emitter.completeWithError(e);
                    } finally {
                        emitter.complete();
                    }
                }
        );
        return emitter;
    }

    @PostMapping("/stream")
    public SseEmitter streamChat(@RequestBody ChatReq request) {
        // 无超时
        SseEmitter emitter = new SseEmitter(-1L);

        // 处理用户消息
        UserMessage userMessage = UserMessage.from(request.getMessage());
        List<ChatMessage> history = request.getHistory() != null ? request.getHistory() : Collections.emptyList();

        // 创建响应处理器
        AtomicReference<StringBuilder> responseBuilder = new AtomicReference<>(new StringBuilder());
        StreamingChatResponseHandler handler = new StreamingChatResponseHandler() {
            @Override
            public void onPartialResponse(String token) {
                try {
                    responseBuilder.get().append(token);
                    emitter.send(SseEmitter.event().name("token").data(token));
                } catch (IOException e) {
                    onError(e);
                }
            }

            @Override
            public void onCompleteResponse(ChatResponse chatResponse) {
                try {
                    emitter.send(SseEmitter.event().name("complete").data(responseBuilder.get().toString()));
                    emitter.complete();
                } catch (IOException e) {
                    onError(e);
                }
            }

            @Override
            public void onError(Throwable throwable) {
                emitter.completeWithError(throwable);
            }
        };

        // 发送聊天消息并处理流式响应
        try {
            // 添加历史消息
            if (history.isEmpty()) {
                ChatRequest chatRequest = ChatRequest.builder().messages(userMessage).build();
                streamingChatLanguageModel.chat(chatRequest, handler);
            } else {
                history.add(userMessage);
               ChatRequest chatRequest = ChatRequest.builder().messages(history).build();
                streamingChatLanguageModel.chat(chatRequest, handler);
            }
        } catch (Exception e) {
            emitter.completeWithError(e);
        }

        // 设置异常处理
        emitter.onTimeout(emitter::complete);
        emitter.onError(throwable -> {
            throwable.printStackTrace();
            emitter.complete();
        });
        return emitter;
    }

}